import java.io.*;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import java.util.Random;



public final class MainGame extends GameCanvas implements Runnable
{
    /* Declare constants used in the game */
    public final int SCREEN_WIDTH;
    public final int SCREEN_HEIGHT;
    static public boolean isGameRunning;
    
    /* Declare all images used in the MainGame class */
    private Image pongTable;
    private Image paddleImage,paddleCCW,paddleCW;
    private Image ballImage;


    static public final int LEFT=1;
    static public final int RIGHT=2;
    static public final int BOTTOM=3;
    static public final int TOP=4;

    static public final int SINGLE=1;
    static public final int HOST=2;
    static public final int JOIN=3;
    static public int mode;

    static private int winner=0;
    /* Declare which images will be used as sprites */
    private Sprite tableSprite;

    static public ball Ball;
    static public Paddle local_paddle;
    static public Paddle top_paddle;
    
    public static LayerManager manager;
    private Thread mainThread;

    private boolean num4check = false;
    private boolean num6check = false;

    static private MobilePong theMidlet;
    public audio Audio;
    
    // Flag to decide if AI paddle should turn CW or CCW
    // false = turnCW, true = turnCCW
    boolean turnCW = false;
    boolean turnMade = false;
    int randNum = 0;

    /*private static final int counterInit=0;
    private int counter=counterInit;*/
    
    public MainGame(MobilePong m, int mode){
        super(true);
        theMidlet = m;
        this.mode=mode;
        setFullScreenMode(true);
        SCREEN_WIDTH = getWidth();
        SCREEN_HEIGHT = getHeight();
        System.out.println("Main Game constructor");
        manager = new LayerManager();
        Audio=new audio();
        loadImages();
        Ball=new ball(SCREEN_WIDTH,SCREEN_HEIGHT,2,ballImage);//table is smaller than screen
        String name=mode==SINGLE?"Computer":"Opponent";
        local_paddle=new Paddle(SCREEN_WIDTH,SCREEN_HEIGHT,BOTTOM,paddleImage,paddleCCW,paddleCW,"Player");
        top_paddle=new Paddle(SCREEN_WIDTH,SCREEN_HEIGHT,TOP,paddleImage,paddleCCW,paddleCW,name);
        loadSprites();
        isGameRunning = true;
        Ball.start();
    }
    
    public void start(){
        mainThread = new Thread(this);        
        mainThread.start();
    }

    public static void stop(){
        isGameRunning = false;
        Ball.stop();
        System.out.println("EXIT THE GAME");
    }   

    public void run(){
        //Graphics g = getGraphics();
        try {
            while(isGameRunning) {                
                checkUserInput();
                collisionDetection();
                repaint();
                if(mode==SINGLE)spAI();
                else top_paddle.simulate();
                Thread.currentThread().sleep(40);
            }
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        }
        System.err.println("MainGame::run() end");
    }
//TODO adjust for non standard screen sizes, both on single and in multiplayer;trying to scale, no-go
    public static Image scale(Image original, int newWidth, int newHeight)
    {
        int[] rawInput = new int[original.getHeight() * original.getWidth()];
        original.getRGB(rawInput, 0, original.getWidth(), 0, 0, original.getWidth(), original.getHeight());

        int[] rawOutput = new int[newWidth*newHeight];

        // YD compensates for the x loop by subtracting the width back out
        int YD = (original.getHeight() / newHeight) * original.getWidth() - original.getWidth();
        int YR = original.getHeight() % newHeight;
        int XD = original.getWidth() / newWidth;
        int XR = original.getWidth() % newWidth;
        int outOffset= 0;
        int inOffset=  0;

        for (int y= newHeight, YE= 0; y > 0; y--) {
            for (int x= newWidth, XE= 0; x > 0; x--) {
                rawOutput[outOffset++]= rawInput[inOffset];
                inOffset+=XD;
                XE+=XR;
                if (XE >= newWidth) {
                    XE-= newWidth;
                    inOffset++;
                }
            }
            inOffset+= YD;
            YE+= YR;
            if (YE >= newHeight) {
                YE -= newHeight;
                inOffset+=original.getWidth();
            }
        }
        return Image.createRGBImage(rawOutput, newWidth, newHeight, false);
    }

    public void loadImages(){
        try{
            //Remember to load the res folder into netbeans
            pongTable = Image.createImage("/PongTable.png");
            
            paddleImage = Image.createImage("/Paddle.png");
            paddleCCW=Image.createImage("/PaddleCCW.png");
            paddleCW=Image.createImage("/PaddleCW.png");

            ballImage = Image.createImage("/PongBall.png");
            scale(pongTable,SCREEN_WIDTH,SCREEN_HEIGHT);
            System.out.println("Loading Images Completed!");
        }
        catch(IOException ioex){
            System.err.println(ioex+" Error in Load Images");
        }
    }
    
    public void loadSprites(){
        tableSprite = new Sprite(pongTable);
        //Remember the z-order
        manager.append(Ball.ballSprite);
        manager.append(local_paddle.paddleSprite);
        manager.append(top_paddle.paddleSprite);
        manager.append(tableSprite);
    }

    public void checkUserInput(){
        int button = getKeyStates();        
        if(((button & LEFT_PRESSED) != 0) || (num4check))       local_paddle.move_left();
        else if(((button & RIGHT_PRESSED) != 0) || (num6check)) local_paddle.move_right();
        else                                                    local_paddle.stop();
        boolean ret=false;
        if((button & GAME_C_PRESSED) != 0){
            ret=local_paddle.rotateCCW();
            if (MobilePong.connectMan != null&&ret) MobilePong.connectMan.sendRotateCCW();
        } else if((button & GAME_D_PRESSED) != 0){
            ret=local_paddle.rotateCW();
            if (MobilePong.connectMan != null&&ret) MobilePong.connectMan.sendRotateCW();
        } else{
            ret=local_paddle.rotateN();
            if (MobilePong.connectMan != null&&ret) MobilePong.connectMan.sendRotateN();
        }
    }

    protected void keyPressed(int keyCode){
        switch(keyCode){
            case Canvas.KEY_NUM7:
            case Canvas.KEY_STAR:
            	local_paddle.rotateCCW();
            	if (MobilePong.connectMan != null)MobilePong.connectMan.sendRotateCCW();
            	break;
            case Canvas.KEY_POUND:
            case Canvas.KEY_NUM9:
            	local_paddle.rotateCW();
            	if (MobilePong.connectMan != null)MobilePong.connectMan.sendRotateCW();
            	break;
            case KEY_NUM4   :num4check = true; break;
            case KEY_NUM6   :num6check = true; break;
        }
    }

    protected void keyRepeated(int keyCode){

    }

    protected void keyReleased(int keyCode){
        switch(keyCode){
            case Canvas.KEY_STAR:case Canvas.KEY_NUM7:case Canvas.KEY_POUND:case Canvas.KEY_NUM9:
            	local_paddle.rotateN();
            	if (MobilePong.connectMan != null)MobilePong.connectMan.sendRotateN();
            	break;
            case KEY_NUM4   :num4check = false; break;
            case KEY_NUM6   :num6check = false; break;
        }
    }

    public void collisionDetection(){
        //if(Ball.ballSprite.getY()>local_paddle.paddleSprite.getHeight()+30&&Ball.ballSprite.getY()<SCREEN_HEIGHT-local_paddle.paddleSprite.getHeight()-30)return;
        if(Ball.ballSprite.collidesWith(local_paddle.paddleSprite, true)){
            Ball.collide(BOTTOM);
        }
        if(Ball.ballSprite.collidesWith(top_paddle.paddleSprite, true)){
            if(mode==SINGLE)
            if((randNum < 50)&&(!turnMade))
            {
                if(turnCW) top_paddle.rotateCW();
                else top_paddle.rotateCCW();
                turnMade = true;
            }
            Ball.collide(TOP);
        }
    }
    
    /* We display the points on the status bar */
    public void paint(Graphics g){
        String score1 = top_paddle.getName()+" :" + top_paddle.getScore();
        String score2 = local_paddle.getName()+" :" + local_paddle.getScore();
        //g.fillRect(0,0,getWidth(),getHeight());
        manager.paint(g, 0, 0);
        g.drawString(score1, 0, 0, Graphics.TOP|Graphics.LEFT);
        g.drawString(score2, 0, SCREEN_HEIGHT-20, Graphics.TOP|Graphics.LEFT);
    }

    /* This function handles the AI of 
	 the opponent during single player */
    public void spAI(){
        //Randomiser to tweak AI behaviour so it is not unbeatable.
        Random randomAI = new Random();
        randNum = randomAI.nextInt(100);

        // Adjust difficulty according to player score
        int diffAI = 4 + local_paddle.getScore();

        int ballPX = Ball.getPosX();
        int ballPY = Ball.getPosY();
        int ballVY = Ball.getVelY();
        int paddlePX = top_paddle.getPosX()+top_paddle.paddleSprite.getWidth()/2;

        int diff = paddlePX - ballPX;

        // Control AI paddle movement
        if(ballVY < 0||Ball.matchOver)
        {
            // Control speed of paddle randomly.
            // Increase AI as player score increases.
            if ((randNum < 25)&&(local_paddle.getScore() < 2))
            { top_paddle.shift = 3; }
            else if ((randNum < 50)&&(local_paddle.getScore() < 4))
            { top_paddle.shift = 4; }
            else if (randNum < 75) { top_paddle.shift = 5; }
            else { top_paddle.shift = 6; }

            if (diff > top_paddle.paddleSprite.getWidth()/4)
            {
		top_paddle.move_left();
                turnCW = true;
            } 
            else if (diff < -top_paddle.paddleSprite.getWidth()/4)
            {
		top_paddle.move_right();
                turnCW = false;
            }
	}

        // Control AI paddle rotation
        if((ballPY > SCREEN_HEIGHT/4)&&turnMade)
        {
            top_paddle.rotateN();
            turnMade = false;
        }
    }

    static void gameOver(boolean iWon) throws InterruptedException{
        int gameOverTime=2000;
        if((winner==BOTTOM&&iWon)||(winner==TOP&&!iWon))return;
        if(iWon){
            Alert gameOver = new Alert("Game Over","You Have Won \nCongrats!!",null,null);
            gameOver.setTimeout(gameOverTime);
            Display.getDisplay(theMidlet).setCurrent(gameOver);
            winner = BOTTOM;
        }else{
            Alert gameOver = new Alert("Game Over","You have Lost.\nBetter Luck Next Time",null,null);
            gameOver.setTimeout(gameOverTime);
            Display.getDisplay(theMidlet).setCurrent(gameOver);
            winner=TOP;
        }
        if(mode==HOST)MobilePong.connectMan.sendGameEnd(winner);
        Thread.sleep(gameOverTime);
        theMidlet.stopGame();
        theMidlet.startMenu();
    }
}
